package main

import (
	"fmt"
	"io"
	"os"
	"path/filepath"
)

// CopyFiles 复制源路径下的所有文件到目标目录
// srcPattern 可以包含通配符，如 "./mysql8.0.28/mysql-8.0.28-winx64/*"
// destDir 是目标目录路径
func CopyFiles(srcPattern, destDir string) error {
	// 获取匹配的所有文件/目录
	matches, err := filepath.Glob(srcPattern)
	if err != nil {
		return fmt.Errorf("解析源路径失败: %w", err)
	}
	if len(matches) == 0 {
		return fmt.Errorf("没有找到匹配的文件")
	}

	// 确保目标目录存在
	if err := os.MkdirAll(destDir, 0o755); err != nil {
		return fmt.Errorf("创建目标目录失败: %w", err)
	}

	// 处理每个匹配项
	for _, srcPath := range matches {
		// 获取文件信息
		info, err := os.Stat(srcPath)
		if err != nil {
			return fmt.Errorf("获取文件信息失败: %w", err)
		}

		// 构建目标路径
		destPath := filepath.Join(destDir, filepath.Base(srcPath))

		if info.IsDir() {
			// 如果是目录，递归复制
			if err := copyDir(srcPath, destPath); err != nil {
				return fmt.Errorf("复制目录失败: %w", err)
			}
		} else {
			// 如果是文件，直接复制
			if err := copyFile(srcPath, destPath); err != nil {
				return fmt.Errorf("复制文件失败: %w", err)
			}
		}
	}

	return nil
}

// copyDir 递归复制目录
func copyDir(srcDir, destDir string) error {
	// 创建目标目录
	if err := os.MkdirAll(destDir, 0o755); err != nil {
		return err
	}

	// 遍历源目录
	return filepath.Walk(srcDir, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}

		// 计算相对路径
		relPath, err := filepath.Rel(srcDir, path)
		if err != nil {
			return err
		}

		destPath := filepath.Join(destDir, relPath)

		if info.IsDir() {
			// 创建目录
			return os.MkdirAll(destPath, info.Mode())
		} else {
			// 复制文件
			return copyFile(path, destPath)
		}
	})
}

// copyFile 复制单个文件
func copyFile(srcFile, destFile string) error {
	// 打开源文件
	src, err := os.Open(srcFile)
	if err != nil {
		return err
	}
	defer src.Close()

	// 创建目标文件
	dest, err := os.Create(destFile)
	if err != nil {
		return err
	}
	defer dest.Close()

	// 复制文件内容
	if _, err = io.Copy(dest, src); err != nil {
		return err
	}

	// 同步到磁盘
	if err = dest.Sync(); err != nil {
		return err
	}

	// 保留文件权限
	info, err := os.Stat(srcFile)
	if err != nil {
		return err
	}

	return os.Chmod(destFile, info.Mode())
}
